使用标准JDK在Java中生成安全的随机AES密钥的推荐方法是什么?
在其他帖子中,我发现了这一点,但是使用a SecretKeyFactory可能是一个更好的主意:
SecretKeyFactory
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); SecureRandom random = new SecureRandom(); // cryptograph. secure random keyGen.init(random); SecretKey secretKey = keyGen.generateKey();
如果答案中包含对为什么这是生成随机密钥的一种好方法的解释,那将是很好的。谢谢!
我将使用您建议的代码,但略作简化:
KeyGenerator keyGen = KeyGenerator.getInstance("AES"); keyGen.init(256); // for example SecretKey secretKey = keyGen.generateKey();
让提供者选择计划如何获得随机性-不要定义可能不如提供者已经选择的东西更好的东西。
该代码示例假定(如Maarten所指出的那样您已配置java.security文件以将首选提供程序包括在列表顶部。如果要手动指定提供程序,只需致电KeyGenerator.getInstance("AES","providerName");。
java.security
KeyGenerator.getInstance("AES","providerName");
使用KeyGenerator将是首选方法。正如Duncan指出的,我肯定会在初始化期间给出密钥大小。KeyFactory是一种应用于预先存在的密钥的方法。
KeyGenerator
好的,让我们深入了解这一点。原则上,AES密钥可以具有任何值。没有(3)DES中的“弱密钥”。也没有像(3)DES奇偶校验位中那样具有特定含义的位。因此,生成密钥就像生成带有随机值的字节数组并SecretKeySpec在其周围创建一个数组一样简单。
但是您使用的方法仍然有一些优势:KeyGenerator专门创建用于生成密钥。这意味着可以针对这一代优化代码。这可能会带来效率和安全性好处。例如,可以对它进行编程以避免出现可能暴露密钥的定时侧通道攻击。请注意,清除所有byte[]包含关键信息的内容可能已经是一个好主意,因为它们可能会泄漏到交换文件中(尽管如此,情况仍然如此)。
此外,如上所述,并非所有算法都使用完全随机密钥。因此使用KeyGenerator可以更轻松地切换到其他算法。不过,更现代的密码只能接受完全随机的密钥。与例如DES相比,这被视为一个主要的好处。
最后,就我而言,这是最重要的原因,该KeyGenerator方法是处理安全令牌(智能卡,TPM,USB令牌或HSM)中的AES密钥的唯一有效方法。如果您使用来创建byte[],SecretKeySpec则密钥必须来自内存。这意味着可以将密钥放入安全令牌中,但是无论如何密钥都将公开在内存中。通常,安全令牌仅与在安全令牌中生成的密钥或通过例如智能卡或密钥仪式注入的密钥一起使用。KeyGenerator可以与提供程序一起提供A ,以便在安全令牌内直接生成密钥。
byte[]
SecretKeySpec
如Duncan的答案所示:始终明确指定密钥大小(和其他任何参数)。不要依赖于供应商违约,因为这将使它不清楚你的应用程序在做,每个供应商都可能有自己的缺省值。
要获得真正的安全密钥,您需要使用硬件安全模块(HSM)来生成和保护密钥。HSM制造商通常会提供JCE提供程序,该提供程序将使用上面的代码为您完成所有密钥生成。